package com.atguigu.gulimall.auth.controller;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.constant.AuthServerConstant;
import com.atguigu.common.exception.BizCodeEnum;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberResponseVo;
import com.atguigu.gulimall.auth.feign.MemberFeignService;
import com.atguigu.gulimall.auth.feign.ThirdPartFeignService;
import com.atguigu.gulimall.auth.vo.UserLoginVo;
import com.atguigu.gulimall.auth.vo.UserRegisterVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.atguigu.common.constant.AuthServerConstant.LOGIN_USER;

/**
 * @Author: fd
 * @Date 2021/8/4 17:19
 * @Description: 登录控制器
 */

@Controller
public class LoginController {

	private final ThirdPartFeignService thirdPartFeignService;

	private final StringRedisTemplate stringRedisTemplate;

	private final MemberFeignService memberFeignService;

	public LoginController(ThirdPartFeignService thirdPartFeignService, StringRedisTemplate stringRedisTemplate,
						   MemberFeignService memberFeignService) {
		this.thirdPartFeignService = thirdPartFeignService;
		this.stringRedisTemplate = stringRedisTemplate;
		this.memberFeignService = memberFeignService;
	}

//	@RequestMapping("/login.html")
//	public String login(){
//		return "login";
//	}
//
//	@RequestMapping("/reg.html")
//	public String reg(){
//		return "reg";
//	}

	@ResponseBody
	@GetMapping(value = "/sms/sendCode")
	public R sendCode(@RequestParam("phone") String phone) {

		// 1、接口防刷
		// 取出当前手机对应缓存中的验证码
		String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
		if (StringUtils.isNotBlank(redisCode)) {
			// 取出验证码存入redis的时间，用当前时间减去存入redis的时间，判断用户手机号是否在60s内发送验证码
			long currentTime = Long.parseLong(redisCode.split("_")[1]);
			if (System.currentTimeMillis() - currentTime < 60000) {
				// 60s内不能再发
				return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_CODE_EXCEPTION.getMessage());
			}
		}

		// 2、验证码的再次效验 redis.存key-phone,value-code
		int code = (int) ((Math.random() * 9 + 1) * 100000);
		String codeNum = String.valueOf(code);
		String redisStorage = codeNum + "_" + System.currentTimeMillis();

		// 存入redis，10分钟有效，防止同一个手机号在60秒内再次发送验证码
		stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone,
				redisStorage,10, TimeUnit.MINUTES);

		// 调用第三方服务发送验证码
		thirdPartFeignService.sendCode(phone, codeNum);

		return R.ok();
	}

	/**
	 *
	 * TODO: 重定向携带数据：利用session原理，将数据放在session中。
	 * TODO:只要跳转到下一个页面取出这个数据以后，session里面的数据就会删掉
	 * TODO：分布下session问题
	 * RedirectAttributes：重定向也可以保留数据，不会丢失
	 * 用户注册
	 * @return
	 */
	@PostMapping(value = "/register")
	public String register(@Valid UserRegisterVo vos, BindingResult result, RedirectAttributes attributes) {

		//如果有错误回到注册页面
		if (result.hasErrors()) {
			Map<String, String> errors = result.getFieldErrors().stream().
					collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
			// model.addAttribute("errors",errors);
			// 使用重定向
			attributes.addFlashAttribute("errors",errors);

			// Request method ‘POST’ not supported
			// 用户注册->regist[POST]  -> 转发/reg.html（路径映射转发默认都是get方式访问的），所以这边需要使用重定向

			// 校验出错，重定向到注册页面
			return "redirect:http://auth.gulimall.com/reg.html";
		}

		//1、校验验证码
		String code = vos.getCode();

		//获取存入Redis里的验证码
		String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vos.getPhone());
		if (StringUtils.isNotBlank(redisCode)) {
			//截取字符串
			if (code.equals(redisCode.split("_")[0])) {
				//删除验证码;令牌机制
				stringRedisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX+vos.getPhone());
				//验证码通过，真正注册，调用远程服务进行注册
				R register = memberFeignService.register(vos);
				if (register.getCode() == 0) {
					//成功
					return "redirect:http://auth.gulimall.com/login.html";
				} else {
					//失败
					Map<String, String> errors = new HashMap<>();
					errors.put("msg", register.getData("msg",new TypeReference<String>(){}));
					attributes.addFlashAttribute("errors",errors);
					return "redirect:http://auth.gulimall.com/reg.html";
				}
			} else {
				//效验出错回到注册页面
				Map<String, String> errors = new HashMap<>();
				errors.put("code","验证码错误");
				attributes.addFlashAttribute("errors",errors);
				return "redirect:http://auth.gulimall.com/reg.html";
			}
		} else {
			//效验出错回到注册页面
			Map<String, String> errors = new HashMap<>();
			errors.put("code","验证码错误");
			attributes.addFlashAttribute("errors",errors);
			return "redirect:http://auth.gulimall.com/reg.html";
		}
	}

	@GetMapping(value = "/login.html")
	public String loginPage(HttpSession session) {

		//从session先取出来用户的信息，判断用户是否已经登录过了
		Object attribute = session.getAttribute(LOGIN_USER);
		//如果用户没登录那就跳转到登录页面
		if (attribute == null) {
			return "login";
		} else {
			return "redirect:http://gulimall.com";
		}

	}


	@PostMapping(value = "/login")
	public String login(UserLoginVo vo, RedirectAttributes attributes, HttpSession session) {

		//远程登录
		R login = memberFeignService.login(vo);

		if (login.getCode() == 0) {
			MemberResponseVo data = login.getData("data", new TypeReference<MemberResponseVo>() {});
			session.setAttribute(LOGIN_USER,data);
			return "redirect:http://gulimall.com";
		} else {
			Map<String,String> errors = new HashMap<>();
			errors.put("msg",login.getData("msg",new TypeReference<String>(){}));
			attributes.addFlashAttribute("errors",errors);
			return "redirect:http://auth.gulimall.com/login.html";
		}
	}


	@GetMapping(value = "/loguot.html")
	public String logout(HttpServletRequest request) {
		request.getSession().removeAttribute(LOGIN_USER);
		request.getSession().invalidate();
		return "redirect:http://gulimall.com";
	}

}
